<?php


namespace app\common\lib\push;


use app\common\lib\apns\ApnsPush;
use app\common\lib\Util;
use app\common\model\UserPush;
use think\Log;
use think\queue\Job;
use XznsTools\cache\CacheManage;
use XznsTools\push\HuaweiV2 as Huawei;
use XznsTools\push\Jpush;
use XznsTools\push\Oppo;
use XznsTools\push\Vivo;
use XznsTools\push\Xiaomi;

class PushJob
{
    protected $pushTokenCacheModel = 'push_token'; //huawei=>5 xiaomi=>4 vivo=>3 oppo=>2 极光=> 1

    /**
     * 批量推送
     * @param Job $job
     * @param $jobData
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public function batchPush(Job $job, $jobData)
    {
        if ($job->attempts() > 1)
        {
            Log::write(date('Y-m-d h:i:s') . '：队列任务执行失败：【' . json_encode($jobData, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) . '】：任务关闭', 'error', true);
            $job->delete();
            return;
        }
        $pushType = (int)($jobData['type'] ?? 0);
        $config = config('push');
        if (isset($jobData['thing_type'], $jobData['push_id']))
        {
            $biTag = ($jobData['thing_type'] ?? '') . '_' . ($jobData['push_id'] ?? '');
        } else
        {
            $biTag = '';
        }

        $pushData = [
            'plantform' => $pushType === 1 ? 1 : 3, // 1 => all  2 => IOS 3 => android
            'title' => $jobData['title'], // 推送标题
            'content' => $jobData['content'], // 推送内容
            'extras' => $jobData['extras'], // 扩展字段
            'informType' => 0, //通知栏样式 0默认 1大文本 2收件箱 3大图片
            'bigText' => '', // 大文本内容
            'bigPicPath' => '', // 大图片路径
            'timeToLive' => 86400, // 默认86400
            'biTag' => $biTag
        ];

        switch ($pushType)
        {
            case 1: // 极光
                $jPush = new Jpush($config['jpush']);

                $p = 0;
                do
                {
                    $regIds = array_slice($jobData['regids'], $p, 999);
                    if ($regIds)
                    {
                        $p += 999;

                        //------------anps------------
                        $is_anps_send_success = false;//是否通过apns发送
                        if (config('push.apns')['is_use'])
                        {
                            try
                            {
                                //所有发送的数据
                                $device_tokens_all = (new UserPush())->whereIn('regid', $regIds)->column('regid,device_token');
                                //apns发送的数据（device_token 数组）
                                $device_tokens_apns = array_values(array_unique(array_filter($device_tokens_all)));
                                //jpush发送的数据（regid 数组）
                                $regids_jpush = array_keys(array_diff($device_tokens_all, $device_tokens_apns));

                                if (!empty($device_tokens_apns))
                                {//apns推送
                                    $apnsPush = new ApnsPush();
                                    $res_apns = $apnsPush->setData($pushData)->push($device_tokens_apns);
                                    if ((int)$res_apns['http_code'] === 200)
                                    {
                                        Log::write('apns推送成功；错误消息：' . json_encode($res_apns, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) . ',推送设备device_token：' . json_encode($device_tokens_apns ?? '') . ',推送设备ID：' . json_encode($regIds) . ',推送消息：' . json_encode($pushData, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE), 'error');
                                        $this->sendMsg('apns推送成功', "## apns推送成功\r\n > 消息：" . json_encode($res_apns, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE));
                                        $res_apns['success'] = true;
                                        $is_anps_send_success = true;
                                    } else
                                    {
                                        Log::write('apns推送失败；错误消息：' . json_encode($res_apns) . ',推送设备device_token：' . json_encode($device_tokens_apns ?? '', JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) . ',推送设备ID：' . json_encode($regIds) . ',推送消息：' . json_encode($pushData, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE), 'error');
                                        $this->sendMsg('apns推送失败', "## apns推送异常\r\n > 错误消息：" . json_encode($res_apns, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE));
                                        $res_apns['success'] = false;
                                    }

                                }
                            }
                            catch (\Exception $e)
                            {
                                Log::write('apns推送失败；错误消息：' . $e->getMessage() . ',推送设备device_token：' . json_encode($device_tokens_apns ?? '') . ',推送设备ID：' . json_encode($regIds) . ',推送消息：' . json_encode($pushData, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE), 'error');
                                $this->sendMsg('apns推送失败', "## apns推送异常\r\n > 错误消息：" . $e->getMessage());
                            }

                        }


                        //apns发送失败，还原极光推送所有的数据
                        if (!$is_anps_send_success)
                        {
                            $regids_jpush = $regIds;
                        }
                        //------------anps------------

//极光推送有问题，先注释掉

//                        try
//                        {
//                            if (isset($regids_jpush))
//                            {
//                                $res = $jPush->setData($pushData)->push($regids_jpush);
//                            } else
//                            {
//                                $res = $jPush->setData($pushData)->push($regIds);
//                            }
//
//                            if ((int)$res['http_code'] !== 200)
//                            {
//                                Log::write('极光推送失败；错误消息：' . json_encode($res) . ',推送设备ID：' . json_encode($regIds) . ',推送消息：' . json_encode($pushData), 'error');
//                                $this->sendMsg('极光推送失败', "## 极光推送异常\r\n > 错误消息：" . json_encode($res));
//                                $md = ['code' => 500, 'msg' => $res];
//                            } else
//                            {
//                                $md = ['code' => 200, 'msg' => $res];
//                            }
//                        }
//                        catch (\Exception $e)
//                        {
//                            Log::write('极光推送失败；错误消息：' . $e->getMessage() . ',推送设备ID：' . json_encode($regIds) . ',推送消息：' . json_encode($pushData), 'error');
//                            $this->sendMsg('极光推送失败', "## 极光推送异常\r\n > 错误消息：" . $e->getMessage());
//                            $md = ['code' => 500, 'msg' => $e->getMessage()];
//                        }

//                        Log::write([
//                            'push_id' => $jobData['push_id'] ?? 0,
//                            'type' => 1,
//                            'code' => $md['code'],
//                            'msg' => $md['msg'],
//                            'title' => $jobData['title'],
//                            'content' => "'" . $jobData['content'] . "'",
//                            'extras' => $jobData['extras'],
//                            'regids' => $regIds,
//                        ], 'flog_push'); // 记录推送信息
                    }
                    sleep(1);
                } while ($regIds);
                break;
            case
            2: // oppo
                $oppoPush = new Oppo($config['oppo']);
                $token = CacheManage::getInstance()->setCacheConfig($this->pushTokenCacheModel, $pushType)->getCache(); // 缓存
                if (!$token)
                {
                    $tokenData = $oppoPush->getAccessToken();
                    if ($tokenData['success'])
                    {
                        $token = $tokenData['data']['data']['auth_token'];
                        // token 写入缓存
                        CacheManage::getInstance()->setCacheConfig($this->pushTokenCacheModel, $pushType)->setCache($token, 'details', false);
                    } else
                    {
                        Log::write([
                            'push_id' => $jobData['push_id'] ?? 0,
                            'type' => 2,
                            'code' => 500,
                            'msg' => $tokenData,
                            'title' => $jobData['title'],
                            'content' => "'" . $jobData['content'] . "'",
                            'extras' => $jobData['extras'],
                            'regids' => $jobData['regids'],
                        ], 'flog_push'); // 记录推送信息
                        Log::write('oppo推送失败；错误消息：' . json_encode($tokenData) . ',推送消息：' . json_encode($jobData), 'error');
                        $this->sendMsg('oppo推送失败', "## oppo推送异常\r\n > 错误消息：" . json_encode($tokenData));
                        $job->delete();
                        return;
                    }
                }

                $p = 0;
                do
                {
                    $regIds = array_slice($jobData['regids'], $p, 999);
                    if ($regIds)
                    {
                        $p += 999;
                        try
                        {
                            $res = $oppoPush->setData($pushData)->batchPushOne($token, $regIds);
                            if (!$res['success'])
                            {
                                Log::write('oppo推送失败；错误消息：' . json_encode($res) . ',推送设备ID：' . json_encode($regIds) . ',推送消息：' . json_encode($pushData), 'error');
                                $this->sendMsg('oppo推送失败', "## oppo推送异常\r\n > 错误消息：" . json_encode($res));
                                $md = ['code' => 500, 'msg' => $res];
                            } else
                            {
                                $md = ['code' => 200, 'msg' => $res];
                            }
                        }
                        catch (\Exception $e)
                        {
                            Log::write('oppo推送失败；错误消息：' . $e->getMessage() . ',推送设备ID：' . json_encode($regIds) . ',推送消息：' . json_encode($pushData), 'error');
                            $this->sendMsg('oppo推送失败', "## oppo推送异常\r\n > 错误消息：" . $e->getMessage());
                            $md = ['code' => 500, 'msg' => $e->getMessage()];
                        }
                        Log::write([
                            'push_id' => $jobData['push_id'] ?? 0,
                            'type' => 2,
                            'code' => $md['code'],
                            'msg' => $md['msg'],
                            'title' => $jobData['title'],
                            'content' => "'" . $jobData['content'] . "'",
                            'extras' => $jobData['extras'],
                            'regids' => $regIds,
                        ], 'flog_push'); // 记录推送信息
                    }
                    sleep(1);
                } while ($regIds);
                break;
            case 3: // vivo
                $vivoPush = new Vivo($config['vivo']);
                $token = CacheManage::getInstance()->setCacheConfig($this->pushTokenCacheModel, $pushType)->getCache(); // 缓存
                if (!$token)
                {
                    $tokenData = $vivoPush->getAccessToken();
                    if ($tokenData['success'] && $tokenData['data']['result'] == 0)
                    {
                        $token = $tokenData['data']['authToken'];
                        // token 写入缓存
                        CacheManage::getInstance()->setCacheConfig($this->pushTokenCacheModel, $pushType)->setCache($token, 'details', false);
                    } else
                    {
                        Log::write([
                            'push_id' => $jobData['push_id'] ?? 0,
                            'type' => 3,
                            'code' => 500,
                            'msg' => $tokenData,
                            'title' => $jobData['title'],
                            'content' => "'" . $jobData['content'] . "'",
                            'extras' => $jobData['extras'],
                            'regids' => $jobData['regids'],
                        ], 'flog_push'); // 记录推送信息
                        Log::write('vivo推送失败；错误消息：' . json_encode($tokenData) . ',推送消息：' . json_encode($jobData), 'error');
                        $this->sendMsg('vivo推送失败', "## vivo推送异常\r\n > 错误消息：" . json_encode($tokenData));
                        $job->delete();
                        return;
                    }
                }

                $p = 0;
                do
                {
                    $regIds = array_slice($jobData['regids'], $p, 999);
                    if ($regIds)
                    {
                        $p += 999;
                        try
                        {
                            if (count($regIds) > 1)
                            {   // 批量单推
                                $res = $vivoPush->setData($pushData)->batchPushOne($token, $regIds);
                            } else
                            {  //单推
                                $res = $vivoPush->setData($pushData)->pushOne($token, current($regIds));
                            }

                            if (!$res['success'] || $res['data']['result'] != 0)
                            {
                                Log::write('vivo推送失败；错误消息：' . json_encode($res) . ',推送设备ID：' . json_encode($regIds) . ',推送消息：' . json_encode($pushData), 'error');
                                $this->sendMsg('vivo推送失败', "## vivo推送异常\r\n > 错误消息：" . json_encode($res));
                                $md = ['code' => 500, 'msg' => $res];
                            } else
                            {
                                $md = ['code' => 200, 'msg' => $res];
                            }
                        }
                        catch (\Exception $e)
                        {
                            Log::write('vivo推送失败；错误消息：' . $e->getMessage() . ',推送设备ID：' . json_encode($regIds) . ',推送消息：' . json_encode($pushData), 'error');
                            $this->sendMsg('vivo推送失败', "## vivo推送异常\r\n > 错误消息：" . $e->getMessage());
                            $md = ['code' => 500, 'msg' => $e->getMessage()];
                        }
                        Log::write([
                            'push_id' => $jobData['push_id'] ?? 0,
                            'type' => 3,
                            'code' => $md['code'],
                            'msg' => $md['msg'],
                            'title' => $jobData['title'],
                            'content' => "'" . $jobData['content'] . "'",
                            'extras' => $jobData['extras'],
                            'regids' => $regIds,
                        ], 'flog_push'); // 记录推送信息
                    }
                    sleep(1);
                } while ($regIds);
                break;
            case 4: // xiaomi
                $miPush = new Xiaomi($config['xiaomi']);

                $p = 0;
                do
                {
                    $regIds = array_slice($jobData['regids'], $p, 999);
                    if ($regIds)
                    {
                        $p += 999;
                        try
                        {
                            $res = $miPush->setData($pushData)->pushOne($regIds);
                            if ($res['result'] != 'ok')
                            {
                                Log::write('小米推送失败；错误消息：' . json_encode($res) . ',推送设备ID：' . json_encode($regIds) . ',推送消息：' . json_encode($pushData), 'error');
                                $this->sendMsg('小米推送失败', "## 小米推送异常\r\n > 错误消息：" . json_encode($res));
                                $md = ['code' => 500, 'msg' => $res];
                            } else
                            {
                                $md = ['code' => 200, 'msg' => $res];
                            }
                        }
                        catch (\Exception $e)
                        {
                            Log::write('小米推送失败；错误消息：' . $e->getMessage() . ',推送设备ID：' . json_encode($regIds) . ',推送消息：' . json_encode($pushData), 'error');
                            $this->sendMsg('小米推送失败', "## 小米推送异常\r\n > 错误消息：" . $e->getMessage());
                            $md = ['code' => 500, 'msg' => $e->getMessage()];
                        }
                        Log::write([
                            'push_id' => $jobData['push_id'] ?? 0,
                            'type' => 4,
                            'code' => $md['code'],
                            'msg' => $md['msg'],
                            'title' => $jobData['title'],
                            'content' => "'" . $jobData['content'] . "'",
                            'extras' => $jobData['extras'],
                            'regids' => $regIds,
                        ], 'flog_push'); // 记录推送信息
                    }
                    sleep(1);
                } while ($regIds);
                break;
            case 5: // huawei
                $hwPush = new Huawei($config['huawei']);
                $token = CacheManage::getInstance()->setCacheConfig($this->pushTokenCacheModel, $pushType . ':v2')->getCache(); // 缓存
                if (!$token)
                {
                    $tokenData = $hwPush->getAccessToken();
                    if ($tokenData['success'])
                    {
                        $token = $tokenData['data']['access_token'];
                        // token 写入缓存
                        CacheManage::getInstance()->setCacheConfig($this->pushTokenCacheModel, $pushType . ':v2')->setCache($token, 'details', false);
                    } else
                    {
                        Log::write([
                            'push_id' => $jobData['push_id'] ?? 0,
                            'type' => 5,
                            'code' => 500,
                            'msg' => $tokenData,
                            'title' => $jobData['title'],
                            'content' => "'" . $jobData['content'] . "'",
                            'extras' => $jobData['extras'],
                            'regids' => $jobData['regids'],
                        ], 'flog_push'); // 记录推送信息
                        Log::write('华为推送失败；错误消息：' . json_encode($tokenData) . ',推送消息：' . json_encode($jobData), 'error');
                        $this->sendMsg('华为推送失败', "## 华为推送异常\r\n > 错误消息：" . json_encode($tokenData));
                        $job->delete();
                        return;
                    }
                }
                $p = 0;
                do
                {
                    $regIds = array_slice($jobData['regids'], $p, 1000);
                    if ($regIds)
                    {
                        $p += 1000;
                        try
                        {
                            $res = $hwPush->setData($pushData)->push($token, $regIds);
                            if (!$res['success'])
                            {
                                Log::write('华为推送失败；错误消息：' . json_encode($res) . ',推送设备ID：' . json_encode($regIds) . ',推送消息：' . json_encode($pushData), 'error');
                                $this->sendMsg('华为推送失败', "## 华为推送异常\r\n > 错误消息：" . json_encode($res));
                                $md = ['code' => 500, 'msg' => $res];
                            } else
                            {
                                $md = ['code' => 200, 'msg' => $res];
                            }
                        }
                        catch (\Exception $e)
                        {
                            Log::write('华为推送失败；错误消息：' . $e->getMessage() . ',推送设备ID：' . json_encode($regIds) . ',推送消息：' . json_encode($pushData), 'error');
                            $this->sendMsg('华为推送失败', "## 华为推送异常\r\n > 错误消息：{$e->getMessage()}");
                            $md = ['code' => 500, 'msg' => $e->getMessage()];
                        }
                        Log::write([
                            'push_id' => $jobData['push_id'] ?? 0,
                            'type' => 5,
                            'code' => $md['code'],
                            'msg' => $md['msg'],
                            'title' => $jobData['title'],
                            'content' => "'" . $jobData['content'] . "'",
                            'extras' => $jobData['extras'],
                            'regids' => $regIds,
                        ], 'flog_push'); // 记录推送信息
                    }
                    sleep(1);
                } while ($regIds);
                break;
            default:
                $job->delete();
                return;
        }

        $job->delete();
        return;
    }

    public function sendMsg($title, $contentMsg)
    {
        $time = time() * 1000;
        $sec = 'SECcd9cc7f9e863073d9ebd0a2d0c9ed2f38d38ffcd67b700866d97ab3f919eb419';
        $sign = urldecode(base64_encode(hash_hmac('sha256', $time . "\n" . $sec, $sec, true)));
        $url = "https://oapi.dingtalk.com/robot/send?access_token=b93977081e77642ab22db0e369abc12e08389a99441b3cc2ed6b3f675d8e9d7e&timestamp={$time}&sign={$sign}";

        Util::sendDingMsg($url, $title, $contentMsg);
    }
}
